# Copyright (C) 2006-2008 by Sergio Pistone
# sergio_pistone@yahoo.com.ar
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

require File.expand_path( File.dirname( __FILE__ ) + "/../utils/strings" )

require "rexml/document"
require "md5"

module Amarok

	@@menues = {}
	@@images_folder = "#{ENV["HOME"]}/.kde/share/apps/amarok/albumcovers/large/"
	@@dcop_path = nil
	@@dcop_dirs = [ "/usr/kde/3.5/bin", "/usr/kde/bin", "/usr/bin" ]

	def Amarok.dcop_path()
		if ! @@dcop_path
			@@dcop_path = `which dcop`.strip()
			if @@dcop_path.empty? # we search other directories
				@@dcop_dirs.each() do |dir|
					@@dcop_path = `which #{dir}/dcop`.strip()
					break if ! @@dcop_path.empty?
				end
			end
			if @@dcop_path.empty?
				`kdialog --passivepopup "<qt><b>Wiki-Lyrics</b><br/>Sorry... could not find <b>dcop</b> program.<br/>No communication with Amarok is possible.</qt>" 5`
				exit 0  # nothing else for us to do as we won't be able to talk to Amarok
			end
		end
		return @@dcop_path
	end

	def Amarok.notify( content )
		return system( Amarok.dcop_path(), "amarok", "playlist", "shortStatusMessage", content )
	end

	def Amarok.popup( content )
		return system( Amarok.dcop_path(), "amarok", "playlist", "popupMessage", content.gsub( "\n", "<br/>" ) )
	end

	# show given text or xml in amarok's lyrics tab
	def Amarok.show_in_lyricstab( content )
		if content.class == REXML::Document
			aux = ""
			content.write( aux )
			content = aux
		end
		return system( Amarok.dcop_path(), "amarok", "contextbrowser", "showLyrics", content )
	end

	def Amarok.build_lyrics( artist, title, lyrics, site, site_url, page_url=nil, add_url=nil )
		xml = REXML::Document.new( "<?xml version='1.0' encoding='UTF-8' ?>" )
		root = xml.add_element( "lyrics" )
		root.add_attribute( "title", title.to_s() )
		root.add_attribute( "artist", artist.to_s() )
		root.add_attribute( "page_url", page_url ) if page_url
		root.add_attribute( "add_url", add_url ) if add_url
		root.add_attribute( "site", site )
		root.add_attribute( "site_url", site_url )
		root.text = lyrics
		aux = ""
		xml.write( aux )
		return aux
	end

	def Amarok.show_lyrics( artist, title, lyrics, site, site_url, page_url=nil, add_url=nil )
		return Amarok.show_in_lyricstab( Amarok.build_lyrics( artist, title, lyrics, site, site_url, page_url, add_url ) )
	end

	def Amarok.build_suggestions( artist, title, suggestions, add_url=nil )
		xml = REXML::Document.new( "<?xml version='1.0' encoding='UTF-8' ?>" )
		root_element = xml.add_element( "suggestions" )
		root_element.add_attribute( "add_url", add_url ) if add_url
		hint = ""
		suggestions.each() do |suggestion|
			if suggestion.is_a?( String )
				hint = "#{suggestion} - " if ! Strings.empty?( suggestion )
				next
			end
			sugg_element = root_element.add_element( "suggestion" )
			sugg_element.add_attribute( "artist", "#{hint}#{suggestion.artist}" )
			sugg_element.add_attribute( "title", suggestion.title )
			sugg_element.add_attribute( "url", suggestion.url )
		end
		aux = ""
		xml.write( aux )
		return aux
	end

	def Amarok.show_suggestions( artist, title, suggestions, add_url=nil )
		return Amarok.show_in_lyricstab( Amarok.build_suggestions( artist, title, suggestions, add_url ) )
	end

	def Amarok.show_not_found( artist, title, add_url=nil )
		return Amarok.show_suggestions( artist, title, [], add_url )
	end

	def Amarok.show_error()
		return Amarok.show_in_lyricstab( "" )
	end

	def Amarok.add_custom_menu_item( menu, item )
		menu_items = @@menues[menu]
		@@menues[menu] = menu_items = [] if menu_items == nil
		menu_items.insert( -1, item ) if ! menu_items.include?( item )
		system( Amarok.dcop_path(), "amarok", "script", "removeCustomMenuItem", menu, item )
		system( Amarok.dcop_path(), "amarok", "script", "addCustomMenuItem", menu, item )
	end

	def Amarok.remove_custom_menu_item( menu, item )
		menu_items = @@menues[menu]
 		if menu_items && menu_items.include?( item )
			menu_items.delete( item )
			@@menues.delete( menu ) if menu_items.empty?
		end
		system( Amarok.dcop_path(), "amarok", "script", "removeCustomMenuItem", menu, item )
	end

	def Amarok.add_custom_checkeable_menu_item( menu, item, checked )
		remove_custom_checkeable_menu_item( menu, item )
		add_custom_menu_item( menu, "[#{checked ? "*" : "  "}] #{item}" )
	end

	def Amarok.remove_custom_checkeable_menu_item( menu, item )
		remove_custom_menu_item( menu, "[*] #{item}" )
		remove_custom_menu_item( menu, "[  ] #{item}" )
	end


	def Amarok.get_custom_menu_item( menu_item_id )
		@@menues.each() do |menu, items|
			items.each() do |item|
				return menu, item if "#{menu} #{item}" == menu_item_id
			end
		end
		return nil, nil
	end

	def Amarok.query( sql_query, keys=nil )
		if keys
			keys_size = keys.size
			results = []
			line_idx = 0
			`#{Amarok.dcop_path()} amarok collection query #{Strings.shell_quote(sql_query)}`.chomp().split( "\n" ).each() do |line|
				result_idx = line_idx / keys_size
				key_idx = line_idx % keys_size
				results[result_idx] = {} if key_idx == 0
				results[result_idx][keys[key_idx]] = line
				line_idx += 1
			end
			return results
		else
			system( Amarok.dcop_path(), "amarok", "collection", "query", sql_query )
			return nil
		end
	end

	def Amarok.query_collection_url( file )
		return nil if file == nil
		root_rs = Amarok.query( "SELECT DISTINCT lastmountpoint FROM devices", ["root"] )
		return nil if root_rs.empty?
		root_rs.each() do |root_r|
			if file.index( root_r["root"] ) == 0
				url = ".#{root_r["root"] == "/" ? file : file.slice( root_r["root"].size..-1 ) }"
				url_rs = Amarok.query( "SELECT url FROM tags WHERE url=#{Strings.sql_quote(url)}", ["url"] )
				return url if url_rs.size == 1
			end
		end
		return nil
	end

# 	def Amarok.debug( message )
# 		system( "kdialog", "--sorry", "<qt>" + message.gsub( "\n", "<br/>" ) + "</qt>" )
# 	end

	# Amarok database tables:
	# =======================
	# - tags:            url dir createdate modifydate album artist composer genre title year comment track
	#                  discnumber bitrate length samplerate filesize filetype sampler bpm deviceid
	# - devices:         id label lastmountpoint uuid servername sharename
	# - artist:          id name
	# - album:           id name
	# - composer:        id name
	# - genre:           id name
	# - year:            id name
	# - lyrics:          url deviceid lyrics uniqueid
	# - images:          path deviceid artist album
	# - labels:          id name type
	# - related_artists: artist suggestion changedate
	# - tags_labels:     deviceid url uniqueid labelid

	def Amarok.query_song_data( file )
		song_data = {}
		if file && (url = Amarok.query_collection_url( file ))
			sql_rs = Amarok.query(
				"SELECT artist.name, tags.title, album.name, year.name " \
				"FROM tags, artist, album, year " \
				"WHERE url=#{Strings.sql_quote(url)} AND artist.id=tags.artist AND album.id=tags.album AND year.id=tags.year",
				["artist", "title", "album", "year"]
			)
			song_data["artist"] = Strings.cleanup_artist( sql_rs[0]["artist"], sql_rs[0]["title"] )
			song_data["title"]  = Strings.cleanup_title( sql_rs[0]["title"] )
 			song_data["album"]  = sql_rs[0]["album"]
			song_data["year"]   = sql_rs[0]["year"]
		end
		return song_data
	end

	def Amarok.query_song_lyrics( file )
		lyrics = nil
		if file && (url = Amarok.query_collection_url( file ))
			sql_rs = Amarok.query( "SELECT lyrics FROM lyrics WHERE url=#{Strings.sql_quote(url)}", ["lyrics"] )
			if sql_rs.size > 0
				lyrics = ""
				sql_rs.each() { |line| lyrics << line["lyrics"] << "\n" }
				begin
					lyrics = REXML::Document.new( lyrics ).root().text()
				rescue Exception
				end
			end
		end
		return lyrics
	end

	def Amarok.debug( text )
		system( "kdialog", "--msgbox", text.to_s )
	end

	def Amarok.query_album_data( file, various_artists="(Various Artists)" )

		album_data = {}

		begin

			if file && (url = Amarok.query_collection_url( file ))
				sql_rs = Amarok.query(
					"SELECT album, year " \
					"FROM tags " \
					"WHERE url=#{Strings.sql_quote(url)}",
					["album_id", "year_id"]
				)

				album_data["album"] = Amarok.query(
					"SELECT name FROM album WHERE id=#{sql_rs[0]["album_id"]}",
					["album"]
				)[0]["album"]

				album_data["year"] = Amarok.query(
					"SELECT name FROM year WHERE id=#{sql_rs[0]["year_id"]}",
					["year"]
				)[0]["year"]

				album_data["tracks"] = Amarok.query(
					"SELECT tags.discnumber, artist.name, tags.title, tags.length " \
					"FROM tags, artist " \
					"WHERE tags.album=#{sql_rs[0]["album_id"]} AND tags.year=#{sql_rs[0]["year_id"]} AND artist.id=tags.artist " \
					"ORDER BY tags.discnumber, tags.track",
					["disc", "artist", "title", "length"]
				)

				if album_data["tracks"].size > 0
					album_data["artist"] = album_data["tracks"][0]["artist"]
					normalized_artist = Strings.normalize( album_data["artist"] )
					album_data["tracks"].each() do |track|
						if normalized_artist != Strings.normalize( track["artist"] )
							album_data["artist"] = various_artists
							break
						end
					end
					album_data["image_path"] = Amarok.get_cover_file( album_data["artist"], album_data["album"] ).to_s()
					album_data["image_path"] = "" if album_data["image_path"] == nil
				else
					album_data["artist"] = ""
					album_data["image_path"] = ""
				end
			end

		rescue NoMethodError # triggered when one of the db queries returns nil
		end

		return album_data
	end

	def Amarok.get_cover_file( artist, album )
		md5sum = MD5.hexdigest( "#{Strings.downcase( artist )}#{Strings.downcase( album )}" )
		return File.exist?( "#{@@images_folder}#{md5sum}" ) ? "#{@@images_folder}#{md5sum}" : nil
	end

	def Amarok.playing?()
		return `#{Amarok.dcop_path()} amarok player isPlaying`.strip() == "true"
	end

	def Amarok.get_current_url()
		url = `#{Amarok.dcop_path()} amarok player encodedURL`.strip()
		url.sub!( /^file:\/+/, "file:/" )
		return url == "" ? nil : url
	end

	def Amarok.get_current_path()
		path = `#{Amarok.dcop_path()} amarok player path`.strip()
		return path.empty? ? nil : path
	end

	def Amarok.get_current_artist()
		artist = `#{Amarok.dcop_path()} amarok player artist`.strip()
		if artist.empty?
			# check if title contains "artist - title" information (happens with radio streams for example)
			tokens = `#{Amarok.dcop_path()} amarok player title`.strip().gsub( "_", " " ).split( " - ", 2 )
			if tokens.size == 2
				tokens[0].strip!()
				artist = tokens[0] if ! tokens[0].empty? && ! tokens[1].strip().empty?
			end
		end
		return artist.empty? ? nil : artist
	end

	def Amarok.get_current_title()
		title = `#{Amarok.dcop_path()} amarok player title`.strip()
		if `#{Amarok.dcop_path()} amarok player artist`.strip().empty?
			# check if title contains "artist - title" information (happens with radio streams for example)
			tokens = title.gsub( "_", " " ).split( " - ", 2 )
			if tokens.size == 2
				tokens[1].strip!()
				title = tokens[1] if ! tokens[0].strip().empty? && ! tokens[1].empty?
			end
		end
		return title.empty? ? nil : title
	end

	def Amarok.get_current_album()
		album = `#{Amarok.dcop_path()} amarok player album`.strip()
		return album.empty? ? nil : album
	end

	def Amarok.get_current_year()
		year = `#{Amarok.dcop_path()} amarok player year`.strip()
		return year.to_i() <= 1900 ? nil : year.to_i()
	end

end
